package com.easy.consumer.compoment;

import com.alibaba.fastjson.JSON;
import com.easy.common.bean.*;
import com.easy.common.exception.ServiceException;
import com.easy.common.service.*;
import com.easy.common.util.SKRequest;
import com.easy.common.util.SYS;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SetOperations;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.concurrent.TimeUnit;

@Component
public class SKConsumer {
    @Autowired
    RedisTemplate redisTemplate;
    @Autowired
    RabbitTemplate rabbitTemplate;
    @DubboReference
    ISeckillResultService seckillResultService;
    @DubboReference
    ISeckillOrderService seckillOrderService;
    @DubboReference
    ISeckillProductService skGoodsService;
    @DubboReference
    IOrderService orderService;
    @DubboReference
    IOrderDetailsService orderDetailsService;
    @DubboReference
    IProductService productService;
    /**
     * 监听秒杀请求队列
     * @param message
     */
    @RabbitListener(queues=SYS.SK_QUEUE)
    public void comsumerMessage(String message){
        try {
            //将队列中的json数据转换成SKRequest对象
            SKRequest skRequest = JSON.parseObject(message, SKRequest.class);

            ValueOperations vos = redisTemplate.opsForValue();
            HashOperations hos=redisTemplate.opsForHash();
            SetOperations sos=redisTemplate.opsForSet();
            //判断是否有秒杀商品存在
            //秒杀商品的KEY
            Integer skgoodsid = skRequest.getSkgoodsid();
            String sk_product_key = SYS.SK_PRE_PRODUCT_KEY + skgoodsid;//redis中存儲的秒殺商品的key對應val是數量
            //秒杀活动的key
            Integer activityid = skRequest.getActivityid();
            String sk_activity_key = SYS.SK_PRE_ACTIVITY_KEY + activityid;

            boolean hasActivity = redisTemplate.hasKey(sk_activity_key);
            int activity_status = (int) hos.get(sk_activity_key, SYS.SK_ACTIVITY_STATUS_HASH_KEY);
            long activity_start_time = (long) hos.get(sk_activity_key, SYS.SK_ACTIVITY_START_TIME_KEY);
            long activity_end_time = (long) hos.get(sk_activity_key, SYS.SK_ACTIVITY_END_TIME_KEY);
            if(!hasActivity||activity_status!=1||System.currentTimeMillis()<activity_start_time||System.currentTimeMillis()>activity_end_time){
                //活动不存在||活动状态异常||活动未开始||活动已结束
                //秒杀失败的信息，将数据保存到秒杀记录表中 ,封装成秒杀记录的数据，转发的死信队列中
                rabbitTemplate.convertAndSend(SYS.SK_EXCHANGE, SYS.SK_DLX_ROUTING_KEY, message);
                //结束流程
                return;
            }
            //获取分布式锁
            //某个秒杀商品的分布式锁的key
            String sk_lock_key = SYS.SK_PRE_LOCK_KEY + skgoodsid;
            while (!vos.setIfAbsent(sk_lock_key, "", SYS.SK_LOCK_EXPIRE_TIME, TimeUnit.MILLISECONDS)) ;
            long a=System.currentTimeMillis();
            //检查用户是否已经抢购  ---  用户允许抢购的数量是可以在钱够商品中设置的
            if(sos.isMember(SYS.SK_RESULT_PRODUCT_SET_KEY+skgoodsid, skRequest.getUserid())){
                //已经抢购过了
                rabbitTemplate.convertAndSend(SYS.SK_EXCHANGE, SYS.SK_DLX_ROUTING_KEY, message);
                //开放分布式锁
                redisTemplate.delete(sk_lock_key);
                //结束流程
                return;
            }
            //秒杀成功在redis中记录秒杀用户的信息--防止超买
            sos.add(SYS.SK_RESULT_PRODUCT_SET_KEY+skgoodsid, skRequest.getUserid());

            //检查秒杀商品的数量,如果数量不足,转发死信,放弃分布式锁,结束流程
            if (vos.get(sk_product_key) == null || Integer.parseInt(vos.get(sk_product_key).toString()) <= 0) {
                //秒殺沒有數量，轉發死信隊列
                rabbitTemplate.convertAndSend(SYS.SK_EXCHANGE, SYS.SK_DLX_ROUTING_KEY, message);
                redisTemplate.delete(sk_lock_key);
                return;
            }
            //先扣数量
            redisTemplate.opsForValue().decrement(sk_product_key);
            //放弃分布式锁
            redisTemplate.delete(sk_lock_key);
            long b=System.currentTimeMillis();
            System.out.println("秒杀成功，耗时："+(b-a));
            //秒杀记录和秒杀订单存储在数据库中
            //封装好SKResult对象
            SeckillResult seckillResult = new SeckillResult();
            seckillResult.setUserId(skRequest.getUserid());
            seckillResult.setProductId(skRequest.getSkgoodsid());
            seckillResult.setActivityId(skRequest.getActivityid());
            seckillResult.setResult((byte)1);
            seckillResult.setId(skRequest.getSkid());
            seckillResult.setSeckillTime(LocalDateTime.now());
            seckillResultService.save(seckillResult);
            //封装订单对象
            //订单
            Order order = new Order();
            order.setUserid(skRequest.getUserid());
            order.setNewtime(LocalDateTime.now());
            order.setOrdertime(LocalDateTime.now());
            order.setStatus(0);
            //获取秒杀商品数据
            SeckillProduct skProduct = skGoodsService.getById(skRequest.getSkgoodsid());
            //对数据库中的数据-1
            skProduct.setStock(skProduct.getStock()-1);
            skGoodsService.updateById(skProduct);

            Product product = productService.getById(skProduct.getProductId());
            order.setPayment(skProduct.getSeckillPrice());
            //保存订单数据,order中id是自增长的,新增后order对象获取订单ID
            orderService.save(order);
            Integer orderId = order.getId();
            //订单明细
            OrderDetails orderDetails = new OrderDetails();
            orderDetails.setOrderid(orderId);
            orderDetails.setProductid(skProduct.getProductId());
            orderDetails.setPrice(skProduct.getSeckillPrice());
            orderDetails.setCount(1);
            orderDetails.setProductname(product.getName());
            orderDetails.setProductimg(product.getImage());
            orderDetailsService.save(orderDetails);
            //秒杀订单
            SeckillOrder seckillOrder = new SeckillOrder();
            seckillOrder.setProductId(skRequest.getSkgoodsid());
            seckillOrder.setUserId(skRequest.getUserid());
            seckillOrder.setOrderId(orderId);
            seckillOrder.setActivityId(skProduct.getActivityId());
            seckillOrderService.save(seckillOrder);
            return;
        }catch(Exception e){
            //失败，将消息转到死信队列
            rabbitTemplate.convertAndSend(SYS.SK_EXCHANGE, SYS.SK_DLX_ROUTING_KEY, message);
            throw new ServiceException(e.getMessage());
        }
    }

    /**
     * 监听死信队列  秒杀失败的消息队列
     * @param message
     */
    @RabbitListener(queues=SYS.SK_DLX_QUEUE)
    public void comsumerDLXMessage(String message){
        //在秒杀记录表中添加一条秒杀失败的记录
    }
}
